import { getRequestHeaders, getApiPrefixV2 } from './request-tools';
import { HttpPortal } from '@shadom/portal-plugin-http';
import { define, transmit, use, defaultOptions } from '@shadom/portal';
import  * as portals  from './portals/portal.idx';
import { fmtPortalMessage, handleResponseStatus}  from './response-handler'

console.log(portals)

use(class extends HttpPortal {
    /**
     * @param {import('@shadom/portal-plugin-http/dist/types/config').HttpPortalConfig} config
     */
    constructor(config) {
        super(config, {
            payload: ['message', 'queries', 'pathParams', 'data'],
            transmit: [],
        });
    }
}, 'HttpPortal');

/**
 * @typedef {import('@shadom/portal').payloadDataSet} PortalPayload
 * @typedef {import('@shadom/portal').PortalResponse} PortalResponse
 */

class PortalError {
    /**
     * Portal没有导出这个类，占位
     * @param {string} message error message
     * @param {Record<string, any>} error error info object
     */
    constructor(message, error) {
        this.message = message;
        this.error = error;
    }
}

const api = process.env.VUE_APP_API || getApiPrefixV2();

Object.assign(defaultOptions, {
    allowDupRequest: true,
    allowExternalKeys: false,
    requestFreezingTime: 400
});

// Register portals
// TODO to compile-time
for (let name in portals) {
    let portal = portals[name];
    
    define({
        ...portal,
        type: portal.type ?? 'HttpPortal',
        name,
        uri: addHostToUri(api, portal.uri)
    });
}


/**
 * 为uri拼接请求host，若Uri中带了https或http则不拼接
 * @param {string} api
 * @param {string} uri 
 */
function addHostToUri(api, uri) {
    uri = uri ?? '';
    if (uri.indexOf('http') === -1 || uri.indexOf('https') === -1) {
        uri = api + uri;
    }
    return uri;
}

/**
 * 
 * @param {PortalError} error 
 */
function handlePortalError(error) {
    fmtPortalMessage(error)
}

/**
 * 把jsonp 和 json请求结果的外层结构统一
 * @typedef {Omit<PortalResponse, 'status'> & {status: {code: number, message?: string, desc?: string}}} normalPortalResponse
 * @param {any} res Origin response data
 * @return {normalPortalResponse}}
 */
function normalizeResponse(res, payload) {
        const isJsonp = res.portal === 'JsonPPortal';
        const { data, raw, status, portal, ticket } = res;
        let /** @type {number} */dataStatusCode = data?.status?.code ?? 0;
        
        // response data
        let responseData = data;

        if(isJsonp) { // 如果是jsonp请求，需要跟json请求格式一致
           dataStatusCode = status === 0 ? 200 : status;
           responseData = { status: { code: dataStatusCode }, data, raw, portal, ticket }
        }

        if ((!isJsonp && dataStatusCode !== 200)) {
            console.warn(`the ${raw.config.url} response data is `, data);
            throw {type: 'StatusError', data: responseData, payload};
        }

    return responseData;
}

/**
 * 获取数据,返回promise对象
 * @param {string} portalName portal name
 * @param {PortalPayload & PortalMessageOptions} payload 请求相关参数 
 * @return {Promise<normalPortalResponse>}>} promise
 */
export function transport(portalName, payload) {
    let headers = getRequestHeaders((payload ?? {headers:{}})?.headers);
    // transmit 发送接口请求
    let res;
    return new Promise(async (resolve, reject) => {
        try {
            res = await transmit(portalName ?? payload.name, Object.assign({}, payload, { headers }));
            // 判断是否是jsonp请求
            
            const response = normalizeResponse(res, payload);
            handleResponseStatus(response, payload);
            resolve(response);
    
        } catch (error) {
            if(error.type === 'StatusError') {
                handleResponseStatus(error.data, error.payload);
                reject(error.data);
                return;
            }
            handlePortalError(error);
            reject(error);
        }
    });
};
